package com.openapi.protocol;

import com.alibaba.fastjson.JSONObject;
import com.openapi.config.JT808ServerConfig;
import com.openapi.config.KafkaProducerConfig;
import com.openapi.data.JT808PackageData;
import com.openapi.data.JT808PushData;
import com.openapi.data.Session;
import com.openapi.data.SessionType;
import com.openapi.protocol.decode.Analyze808;
import com.openapi.protocol.decode.Analyze8082019;
import com.openapi.protocol.encode.*;
import com.openapi.service.KafkaService;
import com.openapi.service.SessionManager;
import com.openapi.service.SessionManagerFactory;
import exsun.jt808.data.base.StatusResult;
import exsun.jt808.data.config.CommonMsgTopic;
import exsun.jt808.data.config.jt808.Jt808DistributeMsgTopic;
import exsun.jt808.data.config.jt808.Jt808MsgIdConfig;
import exsun.jt808.data.config.jt808.Jt808MsgIdTopicDic;
import exsun.jt808.data.distribute_data.DistributeEntity;
import exsun.jt808.data.distribute_data.Qingdao.*;
import exsun.jt808.data.distribute_data.jsatl12.AlarmAttachmentUpload;
import exsun.jt808.data.distribute_data.jt1078.*;
import exsun.jt808.data.distribute_data.jt808.*;
import exsun.jt808.data.enume.OrderSendStatus;
import exsun.jt808.data.upload_data.jt808.QueryServerTimeRequest;
import exsun.jt808.data.util.GsonUtils;
import exsun.jt808.data.util.HostUtil;
import exsun.jt808.data.util.Result;
import io.netty.channel.Channel;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class SendManager {
    private static final Logger logger = LoggerFactory.getLogger(SendManager.class);
    private SessionManager sessionManager;

    public SendManager() {
        this.sessionManager = SessionManager.getInstance();
    }
    @Autowired
    KafkaService kafkaService;

    @Autowired
    private JT808ServerConfig jt808ServerConfig;

    @Autowired
    KafkaProducerConfig kafkaProducerConfig;

    public static final String Text_Send = "Text_Send";

    /**
     * kafka订阅来自网关中心的数据
     * @param records
     * @param ack
     */
    @KafkaListener(id = "${handlecenter.kafka.consumer.distributeConsumerGroup.id}", topics = CommonMsgTopic.distributeData, containerFactory = "HandleCenterBatchRecordConsumerFactory")
    public void channelWriteBatchRecordConsumerListen(List<ConsumerRecord<?, ?>> records, Acknowledgment ack) {
        try {
            for (ConsumerRecord<?, ?> record : records) {
                String msg = null;
                String dvo = null;
                DistributeEntity distributeEntity = null;
                Session session = null;
                try {
                    msg = record.value().toString();
                    logger.info("接收指令数据:{}", msg);
                    distributeEntity = GsonUtils.getObjectFromJson(msg, DistributeEntity.class);
                    distributeEntity.serialNo = getFlowId(distributeEntity.devNo, 0);
                    distributeEntity.msgId = Jt808MsgIdTopicDic.getMsgId(distributeEntity.distributeMsgTopic);
                    distributeEntity.hostName = HostUtil.localHost + ":" + jt808ServerConfig.getJt808ServerPort();
                    String topic = distributeEntity.distributeMsgTopic;
                    dvo = distributeEntity.devNo;
                    JT808PushData pushData = handle(topic, msg);
                    pushData.object.serialNo = distributeEntity.serialNo;
                    SessionManager sessionManager = SessionManagerFactory.GetSessionManager(SessionType.JT_808);
                    session = sessionManager.findByTerminalPhone(pushData.object.devNo);
                    if( session == null){
                        logger.info("session为null:{}", pushData.object.devNo);
                        //Result r = Result.error(1,"设备不在线", msg);
                        StatusResult r = new StatusResult(OrderSendStatus.设备不在线,distributeEntity);
                        kafkaService.pushGeneralData(dvo,CommonMsgTopic.sendResultRData, r);
                        continue;
                    }
                    Channel channel = session.getChannel();
                    channel.writeAndFlush(pushData);
                    // Result r = Result.ok("指令执行成功", distributeEntity);
                    StatusResult r = new StatusResult(OrderSendStatus.发送成功,distributeEntity);
                    kafkaService.pushGeneralData(dvo, CommonMsgTopic.sendResultRData, r);
                }catch (Throwable e){
                    logger.error("{},{}",msg, e);
//                    if( session == null){
//                        logger.info("session为null,不推送失败记录：{}", dvo);
//                        continue;
//                    }
                    //Result r = Result.error(1, e.getMessage()==null ? "指令错误":e.getMessage(),distributeEntity);
                    StatusResult r = new StatusResult(OrderSendStatus.指令参数有误,distributeEntity,e.getMessage());
                    kafkaService.pushGeneralData(dvo,CommonMsgTopic.sendResultRData, r);
                }
            }
            ack.acknowledge();//手动提交偏移量
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private JT808PushData handle(String topic, String msg){
        DistributeEntity distributeEntity = null;
        JT808PushData pushData = null;

        JT808PackageData packageData = new JT808PackageData();
        Package808 pak = getPak(packageData.getVersionId());

        switch (topic){
                 //人工确认报警消息
            case Jt808DistributeMsgTopic.AffirmAlarm_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, AffirmAlarm.class);
                pushData = pak.affirmAlarm_0x8203((AffirmAlarm)distributeEntity);
                break;
                //车辆控制
            case Jt808DistributeMsgTopic.ControlVehicle_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, ControlVehicle.class);
                pushData = pak.controlVehicle_0x8500((ControlVehicle)distributeEntity);
                break;
                //删除圆形区域
            case Jt808DistributeMsgTopic.DelCircleArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, DelCircleArea.class);
                pushData = pak.delCircleArea_0x8601((DelCircleArea)distributeEntity);
                break;
                //删除多边形区域
            case Jt808DistributeMsgTopic.DelPolygonArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, DelPolygonArea.class);
                pushData = pak.delPolygonArea_0x8605((DelPolygonArea)distributeEntity);
                break;
                //删除矩形区域
            case Jt808DistributeMsgTopic.DelRectangleArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, DelRectanglArea.class);
                pushData = pak.delRectangleArea_0x8603((DelRectanglArea)distributeEntity);
                break;
                //删除路线
            case Jt808DistributeMsgTopic.DelRoute_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, DelRoute.class);
                pushData = pak.delRoute_0x8607((DelRoute)distributeEntity);
                break;
                //查询终端参数
            case Jt808DistributeMsgTopic.QueryParameters_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = pak.queryParameters_0x8104(distributeEntity);
                break;
                //位置信息查询
            case Jt808DistributeMsgTopic.QueryPositionInfo_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = pak.QueryPositionInfo_0x8201(distributeEntity);
                break;
                //查询指定终端参数
            case Jt808DistributeMsgTopic.QuerySpecifiedParameters_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, QuerySpecifiedParameters.class);
                pushData = pak.querySpecifiedParameters_0x8106((QuerySpecifiedParameters)distributeEntity);
                break;
                //查询终端属性
            case Jt808DistributeMsgTopic.QueryTerminalProperties_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = pak.queryTerminalProperties_0x8107(distributeEntity);
                break;
                //提问下发
            case Jt808DistributeMsgTopic.QuizSend_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, Quiz.class);
                pushData = pak.quizSend_0x8302((Quiz)distributeEntity);
                break;
                //设置圆形区域
            case Jt808DistributeMsgTopic.SetCircleArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, SetCircleArea.class);
                pushData = pak.setCircleArea_0x8600((SetCircleArea)distributeEntity);
                break;
                //设置终端参数
            case Jt808DistributeMsgTopic.SetParameters_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, SetParameters.class);
                pushData = pak.setParameters_0x8103((SetParameters)distributeEntity);
                break;
                //设置多边形区域
            case Jt808DistributeMsgTopic.SetPolygonArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, SetPolygonArea.class);
                pushData = pak.setPolygonArea_0x8604((SetPolygonArea)distributeEntity);
                break;
                //设置矩形区域
            case Jt808DistributeMsgTopic.SetRectanglArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, SetRectanglArea.class);
                pushData = pak.setRectanglArea_0x8602((SetRectanglArea)distributeEntity);
                break;
                //设置路线
            case Jt808DistributeMsgTopic.SetRoute_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, SetRoute.class);
                pushData = pak.setRoute_0x8606((SetRoute)distributeEntity);
                break;
                //摄像头立即拍摄命令
            case Jt808DistributeMsgTopic.TakePhotoRightAway_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, TakePhotoRightAway.class);
                pushData = pak.takePhotoRightAway_0x8801((TakePhotoRightAway)distributeEntity);
                break;
                //终端控制
            case Jt808DistributeMsgTopic.TerminalControl_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, TerminalControl.class);
                pushData = pak.terminalControl_0x8105((TerminalControl)distributeEntity);
                break;
                //文本信息下发
            case Jt808DistributeMsgTopic.Text_Send:
                JSONObject jsonObject= JSONObject.parseObject(msg);
                if (jsonObject.get("flag") == null){
                    distributeEntity = GsonUtils.getObjectFromJson(msg,TextSend.class);
                    pushData = pak.text_send((TextSend) distributeEntity);
                    break;
                }else {
                    distributeEntity = GsonUtils.getObjectFromJson(msg, Text.class);
                    pushData = pak.text_0x8300((Text)distributeEntity);
                    break;
                }
                //临时位置跟踪控制
            case Jt808DistributeMsgTopic.TracePositionInfo_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, TracePositionInfo.class);
                pushData = pak.tracePositionInfo_0x8202((TracePositionInfo)distributeEntity);
                break;
                //文件上传控制
            case Jt808DistributeMsgTopic.FileUploadCmd_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, FileUploadCmd.class);
                pushData = Package1078.fileUploadCmdEncode((FileUploadCmd)distributeEntity);
                break;
                //文件上传指令
            case Jt808DistributeMsgTopic.FileUploadReq_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, FileUploadReq.class);
                pushData = Package1078.fileUploadReqEncode((FileUploadReq)distributeEntity);
                break;
                //远程录像回放控制
            case Jt808DistributeMsgTopic.HisMediaUploadCmd_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, HisMediaUploadCmd.class);
                pushData = Package1078.hisMediaUploadCmdEncode((HisMediaUploadCmd)distributeEntity);
                break;
                //远程录像回放请求
            case Jt808DistributeMsgTopic.HisMediaUploadReq_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, HisMediaUploadReq.class);
                pushData = Package1078.hisMediaUploadReqEncode((HisMediaUploadReq)distributeEntity);
                break;
                //查询资源列表
            case Jt808DistributeMsgTopic.QueryMediaList_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, QueryMediaList.class);
                pushData = Package1078.queryMediaListEncode((QueryMediaList)distributeEntity);
                break;
                //查询终端音视频属性
            case Jt808DistributeMsgTopic.QueryMediaProperty_Send:
                pushData = Package1078.queryMediaPropertyEncode(distributeEntity);
                break;
                //实时音视频传输控制
            case Jt808DistributeMsgTopic.RealtimeMediaUploadCmd_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, RealtimeMediaUploadCmd.class);
                pushData = Package1078.realtimeMediaUploadCmdEncode((RealtimeMediaUploadCmd)distributeEntity);
                break;
                //实时音视频传输请求
            case Jt808DistributeMsgTopic.RealtimeMediaUploadReq_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, RealtimeMediaUploadReq.class);
                pushData = Package1078.realtimeMediaUploadReqEncode((RealtimeMediaUploadReq)distributeEntity);
                break;
                //报警附件上传指令
            case Jt808DistributeMsgTopic.AlarmAttachmentUpload_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, AlarmAttachmentUpload.class);
                pushData = PackageHj212.alarmAttachmentUploadEncode((AlarmAttachmentUpload)distributeEntity);
                break;
            //数据下行透传
            case Jt808DistributeMsgTopic.IssueOSPF_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,IssueOSPF.class);
                pushData = ((Package8082019)pak).issueOSPFDecoder((IssueOSPF) distributeEntity);
                break;
            //智能终端协议上传数据处理
            //处置证下发
            case Jt808DistributeMsgTopic.HandleIssue_send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,HandleIssue.class);
                pushData = PackageQingdao.HandleIssue((HandleIssue) distributeEntity);
                break;
            //管控开关定义
            case Jt808DistributeMsgTopic.ControlSwitchDefinition_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, ControlSwitchDefinition.class);
                pushData = PackageQingdao.ControlSwitchDefinition((ControlSwitchDefinition) distributeEntity);
                break;
            //管控开关查询
            case Jt808DistributeMsgTopic.ControlSwitchSort_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = PackageQingdao.controlSwitchSort(distributeEntity);
                break;
            //管控开关状态控制
            case Jt808DistributeMsgTopic.ControlSwitchStatus_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,ControlSwitchStatus.class);
                pushData = PackageQingdao.controlSwitchStatus((ControlSwitchStatus) distributeEntity);
                break;
            //管控开关状态查询
            case Jt808DistributeMsgTopic.ControlSwitchStatusSort_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = PackageQingdao.controlSwitchStatusSort(distributeEntity);
                break;
            //新增多边形区域（围栏）
            case Jt808DistributeMsgTopic.AddPolygonArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,AddPolygonArea.class);
                pushData = PackageQingdao.addPolygonArea((AddPolygonArea) distributeEntity);
                break;
            //删除多边形区域
            case Jt808DistributeMsgTopic.DeletePolygonArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg, DeletePolygonArea.class);
                pushData = PackageQingdao.deletePolygonArea((DeletePolygonArea) distributeEntity);
                break;
            //查询多边形区域
            case Jt808DistributeMsgTopic.SortPolygonArea_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = PackageQingdao.sortPolygonArea(distributeEntity);
                break;
            //新增线路
            case Jt808DistributeMsgTopic.AddRoute_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,AddRoute.class);
                pushData = PackageQingdao.addRoute((AddRoute) distributeEntity);
                break;
            //删除线路
            case Jt808DistributeMsgTopic.DeleteRoute_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DeleteRoute.class);
                pushData = PackageQingdao.deleteRoute((DeleteRoute)distributeEntity);
                break;
            //查询线路
            case Jt808DistributeMsgTopic.SortRoute_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = PackageQingdao.sortRoute(distributeEntity);
                break;
            //限举指令下发
            case Jt808DistributeMsgTopic.LimitLeftIssue_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,LimitLeftIssue.class);
                pushData = PackageQingdao.limitLeftIssue((LimitLeftIssue) distributeEntity);
                break;
            //限速指令下发
            case Jt808DistributeMsgTopic.LimitSpeedIssue_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,LimitSpeedIssue.class);
                pushData = PackageQingdao.limitSpeedIssue((LimitSpeedIssue) distributeEntity);
                break;
            //锁车指令
            case Jt808DistributeMsgTopic.LockCar_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,LockCar.class);
                pushData = PackageQingdao.lockCar((LockCar) distributeEntity);
                break;
            //驾驶员人脸库同步
            case Jt808DistributeMsgTopic.DriverFace_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DriverFace.class);
                pushData = PackageQingdao.driverFace((DriverFace) distributeEntity);
                break;
            //驾驶员信息查询
            case Jt808DistributeMsgTopic.DriverMsgSort_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = PackageQingdao.driverMsgSort(distributeEntity);
                break;
            //驾驶员对比结果上报应答
            case Jt808DistributeMsgTopic.DriverContrastResultRes:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DriverContrastResultResponse.class);
                pushData = PackageQingdao.driverContrastResultResponse((DriverContrastResultResponse) distributeEntity);
                break;
            //设备录入驾驶员信息上报应答
            case Jt808DistributeMsgTopic.DeviceInput_Response:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DeviceInput.class);
                pushData = PackageQingdao.deviceInput((DeviceInput) distributeEntity);
                break;
            //远程升级指令
            case Jt808DistributeMsgTopic.RemoteUpgrade_send:
                distributeEntity=GsonUtils.getObjectFromJson(msg,RemoteUpgrade.class);
                pushData= PackageQingdao.remoteUpgrade((RemoteUpgrade)distributeEntity);
                break;
            //设备版本查询
            case Jt808DistributeMsgTopic.DeviceVersionQuery_send:
                distributeEntity=GsonUtils.getObjectFromJson(msg, DeviceVersionQuery.class);
                pushData=PackageQingdao.deviceVersionQuery((DeviceVersionQuery)distributeEntity);
                break;
            //链路检测
            case Jt808DistributeMsgTopic.LinkDetection_send:
                distributeEntity=GsonUtils.getObjectFromJson(msg, DistributeEntity.class);
                pushData= ((Package8082019)pak).linkDetection_0x8204(distributeEntity);
                break; 
           //查询区域或线路数据
            case Jt808DistributeMsgTopic.QueryAreaOrLineData_send:
                distributeEntity=GsonUtils.getObjectFromJson(msg, QueryAreaOrLineData.class);
                pushData=((Package8082019)pak).queryAreaOrLineData_0x8608((QueryAreaOrLineData) distributeEntity);
                break;
            //查询服务器时间应答
            case Jt808DistributeMsgTopic.QueryServerTimeResponse_send:
                distributeEntity=GsonUtils.getObjectFromJson(msg, QueryServerTimeResponse.class);
                pushData=((Package8082019)pak).queryServerTimeResponse_0x8004((QueryServerTimeResponse) distributeEntity);
                break;
            //黑车稽查
            case Jt808DistributeMsgTopic.IllegalCarCheck_Send:
                distributeEntity = GsonUtils.getObjectFromJson(msg,IllegalCarCheck.class);
                pushData = pak.IllegalCarCheck_0x8624((IllegalCarCheck) distributeEntity);
                break;
            //农机设备自动标定
            case Jt808DistributeMsgTopic.AutoCalibration:
                distributeEntity = GsonUtils.getObjectFromJson(msg,DistributeEntity.class);
                pushData = pak.AutoCalibration(distributeEntity);
                break;
            default:
                break;
        }
        return pushData;
    }


    private Package808 getPak(Integer version){
        Package808 pak = null;
        if(version == null|| version == 0){
            pak = new Package808();
        }else{
            pak = new Package8082019();
        }
        return pak;
    }

    private int getFlowId(String terminalPhone, int defaultValue) {
        SessionManager sessionManager = SessionManagerFactory.GetSessionManager(SessionType.JT_808);
        Session session = sessionManager.findByTerminalPhone(terminalPhone);
        if (session == null) {
            return defaultValue;
        }
        return session.currentFlowId();
    }

}


